using System;
using System.Collections.Generic;
using System.Text;
using Jbe.TestSuite.Infrastructure.Interface.Services;
using System.Collections.ObjectModel;
using Microsoft.Practices.CompositeUI.Commands;
using Jbe.TestSuite.Infrastructure.Interface.Constants;
using System.Windows.Forms;
using System.IO;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.Utility;

namespace Jbe.TestSuite.Infrastructure.Module.Services
{
    public class DocumentManager : IDocumentManager, IDisposable
    {
        private Dictionary<string, IDocumentFactory> documentFactories;
        private IDocument activeDocument;
        private OpenFileDialog openFileDialog;
        private SaveFileDialog saveFileDialog;
        private WorkItem workItem;
        private IUIElementCreationService uiElementCreationService;

        [ServiceDependency]
        public WorkItem WorkItem
        {
            set 
            { 
                workItem = value;
                ActiveDocument = null;
                workItem.Commands[CommandNames.Open].Status = CommandStatus.Disabled;
            }
        }

        [ServiceDependency]
        public IUIElementCreationService UIElementCreationService
        {
            set { uiElementCreationService = value; }
        }

        public ReadOnlyCollection<IDocumentType> DocumentTypes
        {
            get 
            {
                IDocumentType[] array = new IDocumentType[documentFactories.Count];
                int i = 0;
                foreach (IDocumentFactory factory in documentFactories.Values)
                {
                    array[i] = factory;
                    i++;
                }
                return new ReadOnlyCollection<IDocumentType>(array);
            }
        }

        private IDocument ActiveDocument
        {
            get { return activeDocument; }
            set 
            { 
                activeDocument = value;

                CommandStatus status = CommandStatus.Disabled;
                if (activeDocument != null) { status = CommandStatus.Enabled; }
                
                workItem.Commands[CommandNames.Save].Status = status;
                workItem.Commands[CommandNames.SaveAs].Status = status;
            }
        }

        public DocumentManager()
        {
            documentFactories = new Dictionary<string, IDocumentFactory>();
            openFileDialog = new OpenFileDialog();
            saveFileDialog = new SaveFileDialog();
        }

        ~DocumentManager()
        {
            Dispose(false);
        }

        public void Register(IDocumentFactory documentFactory)
        {
            documentFactories.Add(documentFactory.Extension, documentFactory);
            openFileDialog.Filter = AppendFilter(openFileDialog.Filter, documentFactory);

            NewDocumentEventHandler handler = new NewDocumentEventHandler(this, documentFactory);
            IMenuItem menuItem = uiElementCreationService.CreateMenuItem(documentFactory.Description);
            IToolBarItem toolBarItem = uiElementCreationService.CreateToolBarItem(documentFactory.Description);
            workItem.UIExtensionSites[UIExtensionSiteNames.NewMenuItem].Add(menuItem);
            workItem.UIExtensionSites[UIExtensionSiteNames.NewToolBarItem].Add(toolBarItem);
            menuItem.Click += handler.EventHandler;
            toolBarItem.Click += handler.EventHandler;

            if (documentFactories.Count == 1) 
            { 
                workItem.Commands[CommandNames.Open].Status = CommandStatus.Enabled; 
            }
        }

        public void New(IDocumentType documentType)
        {
            IDocumentFactory factory = (IDocumentFactory)documentType;
            IDocument document = factory.New();
            if (document != null) { InitializeDocument(document); }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (openFileDialog != null) { openFileDialog.Dispose(); }
                if (saveFileDialog != null) { saveFileDialog.Dispose(); }
            }
        }

        private void Save(string fileName)
        {
            if (fileName == null)
            {
                saveFileDialog.Filter = AppendFilter("", ActiveDocument.DocumentType);

                if (saveFileDialog.ShowDialog() != DialogResult.OK) { return; }
                
                fileName = saveFileDialog.FileName;
            }

            ActiveDocument.Save(fileName);
        }

        private void InitializeDocument(IDocument document)
        {
            document.DocumentActivated += new EventHandler(DocumentActivated);
            document.DocumentDeactivated += new EventHandler(DocumentDeactivated);
            document.Disposed += new EventHandler(DocumentDisposed);
            ActiveDocument = document;
        }

        private static string AppendFilter(string filter, IDocumentType extension)
        {
            if (!String.IsNullOrEmpty(filter)) { filter += "|"; }
            filter += extension.Description + "|*" + extension.Extension;
            return filter;
        }

        #region Command and Event handler

        [CommandHandler(CommandNames.Open)]
        public void Open(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string extension = Path.GetExtension(openFileDialog.FileName);
                
                IDocumentFactory documentFactory = documentFactories[extension];
                IDocument document = documentFactory.Open(openFileDialog.FileName);

                if (document != null) { InitializeDocument(document); }
            }
        }

        [CommandHandler(CommandNames.Save)]
        public void Save(object sender, EventArgs e)
        {
            Save(ActiveDocument.FileName);
        }

        [CommandHandler(CommandNames.SaveAs)]
        public void SaveAs(object sender, EventArgs e)
        {
            Save(null);
        }

        private void DocumentActivated(object sender, EventArgs e)
        {
            ActiveDocument = (IDocument)sender;
        }

        private void DocumentDeactivated(object sender, EventArgs e)
        {
            ActiveDocument = null;
        }

        private void DocumentDisposed(object sender, EventArgs e)
        {
            IDocument document = (IDocument)sender;
            document.DocumentActivated -= DocumentActivated;
            document.DocumentDeactivated -= DocumentDeactivated;
            document.Disposed -= DocumentDisposed;
            ActiveDocument = null;
        }

        #endregion

        private class NewDocumentEventHandler
        {
            private DocumentManager documentManager;
            private IDocumentType documentType;

            public NewDocumentEventHandler(DocumentManager documentManager, IDocumentType documentType)
            {
                this.documentManager = documentManager;
                this.documentType = documentType;
            }

            public void EventHandler(object sender, EventArgs e)
            {
                documentManager.New(documentType);
            }
        }
    }
}
